//////////////////////////////////////////////////////////////////////
//
//  University of Leeds
//  COMP 5812M Foundations of Modelling & Rendering
//  User Interface for Coursework
////////////////////////////////////////////////////////////////////////


#include <math.h>
#include <random>
#include <QTimer>
// include the header file
#include "RaytraceRenderWidget.h"
#include "scene.h"
#include <algorithm>
#include <random>
#include <cmath>


#define N_THREADS 16
#define N_LOOPS 100
#define N_BOUNCES 5
#define TERMINATION_FACTOR 0.35f



// constructor
RaytraceRenderWidget::RaytraceRenderWidget
        (   
        // the geometric object to show
        std::vector<ThreeDModel>      *newTexturedObject,
        // the render parameters to use
        RenderParameters    *newRenderParameters,
        // parent widget in visual hierarchy
        QWidget             *parent
        )
    // the : indicates variable instantiation rather than arbitrary code
    // it is considered good style to use it where possible
    : 
    // start by calling inherited constructor with parent widget's pointer
    QOpenGLWidget(parent),
    // then store the pointers that were passed in
    texturedObjects(newTexturedObject),
    renderParameters(newRenderParameters)
    { // constructor
    //create a QTimer
    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &RaytraceRenderWidget::forceRepaint);
    timer->start(30);
    } // constructor


// destructor
RaytraceRenderWidget::~RaytraceRenderWidget()
    { // destructor
    // empty (for now)
    // all of our pointers are to data owned by another class
    // so we have no responsibility for destruction
    // and OpenGL cleanup is taken care of by Qt
    } // destructor                                                                 

// mouse-handling
void RaytraceRenderWidget::mousePressEvent(QMouseEvent *event)
    { // RaytraceRenderWidget::mousePressEvent()
    // store the button for future reference
    int whichButton = int(event->button());
    // scale the event to the nominal unit sphere in the widget:
    // find the minimum of height & width   
    float size = (width() > height()) ? height() : width();
    // scale both coordinates from that
    float x = (2.0f * event->x() - size) / size;
    float y = (size - 2.0f * event->y() ) / size;

    
    // and we want to force mouse buttons to allow shift-click to be the same as right-click
    unsigned int modifiers = event->modifiers();
    
    // shift-click (any) counts as right click
    if (modifiers & Qt::ShiftModifier)
        whichButton = Qt::RightButton;
    
    // send signal to the controller for detailed processing
    emit BeginScaledDrag(whichButton, x,y);
    } // RaytraceRenderWidget::mousePressEvent()
    
void RaytraceRenderWidget::mouseMoveEvent(QMouseEvent *event)
    { // RaytraceRenderWidget::mouseMoveEvent()
    // scale the event to the nominal unit sphere in the widget:
    // find the minimum of height & width   
    float size = (width() > height()) ? height() : width();
    // scale both coordinates from that
    float x = (2.0f * event->x() - size) / size;
    float y = (size - 2.0f * event->y() ) / size;
    
    // send signal to the controller for detailed processing
    emit ContinueScaledDrag(x,y);
    } // RaytraceRenderWidget::mouseMoveEvent()
    
void RaytraceRenderWidget::mouseReleaseEvent(QMouseEvent *event)
    { // RaytraceRenderWidget::mouseReleaseEvent()
    // scale the event to the nominal unit sphere in the widget:
    // find the minimum of height & width   
    float size = (width() > height()) ? height() : width();
    // scale both coordinates from that
    float x = (2.0f * event->x() - size) / size;
    float y = (size - 2.0f * event->y() ) / size;
    
    // send signal to the controller for detailed processing
    emit EndScaledDrag(x,y);
    } // RaytraceRenderWidget::mouseReleaseEvent()

// called when OpenGL context is set up
void RaytraceRenderWidget::initializeGL()
    { // RaytraceRenderWidget::initializeGL()
	// this should remain empty
    } // RaytraceRenderWidget::initializeGL()

// called every time the widget is resized
void RaytraceRenderWidget::resizeGL(int w, int h)
    { // RaytraceRenderWidget::resizeGL()
    // resize the render image
    frameBuffer.Resize(w, h);
    } // RaytraceRenderWidget::resizeGL()
    
// called every time the widget needs painting
void RaytraceRenderWidget::paintGL()
    { // RaytraceRenderWidget::paintGL()
    // set background colour to white
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    // and display the image
    glDrawPixels(frameBuffer.width, frameBuffer.height, GL_RGBA, GL_UNSIGNED_BYTE, frameBuffer.block);
    } // RaytraceRenderWidget::paintGL()

void RaytraceRenderWidget::Raytrace()
{
    std::cout <<"One day I will raytrace." << std::endl;
    raytracingThread= std::thread(&RaytraceRenderWidget::newRaytraceThread,this);
    raytracingThread.detach();
//    raytracingThread= std::thread(&RaytraceRenderWidget::RaytraceThread,this);
//    raytracingThread.detach();

}

Homogeneous4 RaytraceRenderWidget::TraceAndShadeWithRay(Ray r,int recursionDepth,float weight){

    //生成一个新的，根据光线r计算距离最近的三角形newci
    //光线与三角形相交检测
    Scene::CollisionInfo newci = scene->closestTriangle(r);
    Homogeneous4 newfinalColor;
    //t正负
    if(newci.t>0){
        //计算交点坐标和交点在三角形局部坐标系中的重心坐标
        //计算交点
        Cartesian3 newintersectP = r.origin + newci.t * r.direction;
        //计算重心坐标
        Cartesian3 newbc = newci.tri.baricentric(newintersectP);
        //计算表面法线
        Cartesian3 intersectNormal = (newci.tri.normals[0].Vector() * newbc.x +
                                      newci.tri.normals[1].Vector() * newbc.y +
                                      newci.tri.normals[2].Vector() * newbc.z).unit();
        //计算反射光线
        Ray reflectedRay = reflectRay(r, intersectNormal, newintersectP);
        Homogeneous4 reflectedColor;

        Homogeneous4 surfaceColor(0,0,0,1);
        Homogeneous4 ambientColor(newci.tri.shared_material->ambient.x,newci.tri.shared_material->ambient.y,newci.tri.shared_material->ambient.z,1);
        Homogeneous4 emittedColor(newci.tri.shared_material->emissive.x,newci.tri.shared_material->emissive.y,newci.tri.shared_material->emissive.z,1);

        //判断是否在阴影里
        bool isShadowed = true;

        //遍历每一条光线
        for (const Light* light : renderParameters->lights){
            //如果光亮
            if(light->enabled){

                Matrix4 modelview = scene->getModelview();

                Homogeneous4 lightPosition = modelview * light->GetPositionCenter();

                //从表面点到光源的向量
                Cartesian3 lighDirection=lightPosition.Point() - newintersectP;

                float attenuation = 1.0f / (1.0f + pow(lighDirection.length(), 2));

                Homogeneous4 lightcolor = light->GetColor();
                lightcolor = lightcolor * attenuation;

                //定义环境光
                Homogeneous4 ambientlightcolor(0.5,0.5,0.5,1);
                ambientColor = ambientlightcolor.modulate(ambientColor);

                float epsilon=0.00001f;

                // 生成阴影射线
                //从三角形向光源发出一条射线，当再次碰撞到其他三角形，则说明会生成阴影
                Ray shadowRay(newintersectP + intersectNormal*epsilon, lighDirection.unit());

                // 检查阴影射线是否与其他三角形相交
                Scene::CollisionInfo shadowCollision = scene->closestTriangle(shadowRay);

                if(shadowCollision.t > 0){
                    //如果相交的是光源本身
                    if(shadowCollision.tri.shared_material->isLight())
                    {
                        isShadowed=false;
                    }
                }

                if(isShadowed){
                    surfaceColor = ambientColor + emittedColor;
                }
                else{
                    surfaceColor = newci.tri.calculateBlinnPhongShading(lightPosition,lightcolor,newbc)+ ambientColor +emittedColor + surfaceColor;
                }

              }
            }//遍历光线,分别计算阴影内部和阴影外部的surfaceColor


            //迭代生成reflectedColor
            if(recursionDepth>0 && newci.tri.shared_material->reflectivity > 0)
            {
                //计算镜面反射表面颜色
                reflectedColor = TraceAndShadeWithRay(reflectedRay, recursionDepth - 1, weight);
                //std::cout<<"1345"<<std::endl;
            }
            //将反射光线的颜色与反射率混合
            newfinalColor = newci.tri.shared_material->reflectivity * reflectedColor +
                                         (1.0f - newci.tri.shared_material->reflectivity) * surfaceColor;


        }

        return newfinalColor;

}


Homogeneous4 RaytraceRenderWidget::RefractionWithFrensel(Ray r,int recursionDepth,float weight)
{

    //找到与光线相交的最近的三角形
    Scene::CollisionInfo ci = scene->closestTriangle(r);
    //定义颜色
    Homogeneous4 finalcolor(0,0,0,1);
    if(ci.t <= 0)return finalcolor;

    Homogeneous4 color(0,0,0,1);
    Homogeneous4 reflectedColor;
    Homogeneous4 refractedColor;

    //计算交点
    Cartesian3 intersectP = r.origin + ci.t * r.direction;
    //计算重心坐标
    Cartesian3 bc = ci.tri.baricentric(intersectP);
    //计算表面法线
    Cartesian3 intersectNormal = (ci.tri.normals[0].Vector() * bc.x +
                                  ci.tri.normals[1].Vector() * bc.y +
                                  ci.tri.normals[2].Vector() * bc.z).unit();
    //重心坐标插值 P
    Cartesian3 Position = ci.tri.verts[0].Point() * bc.x+
                          ci.tri.verts[1].Point() * bc.y+
                          ci.tri.verts[2].Point() * bc.z;

    //环境光
    Homogeneous4 ambientColor(ci.tri.shared_material->ambient.x,ci.tri.shared_material->ambient.y,ci.tri.shared_material->ambient.z,1);
    //自发光
    Homogeneous4 emittedColor(ci.tri.shared_material->emissive.x,ci.tri.shared_material->emissive.y,ci.tri.shared_material->emissive.z,1);

    color = color + emittedColor + ambientColor;


    //遍历每一条光线
    for (const Light* light : renderParameters->lights){
        //如果光亮
        if(light->enabled){

        // 计算光的颜色
        Matrix4 modelview = scene->getModelview();
        Homogeneous4 lightPosition = modelview * light->GetPositionCenter();
        Cartesian3 lighDirection=lightPosition.Point() - intersectP;
        float attenuation = 1.0f / (1.0f + pow(lighDirection.length(), 2));
        Homogeneous4 lightcolor = light->GetColor();
        //lightcolor = lightcolor * attenuation;
        //计算没有折射的表面颜色
        color = ci.tri.calculateBlinnPhongShading(lightPosition,lightcolor,bc)+ color + emittedColor + ambientColor;

        }
    }
    //如果物体透明
    if(ci.tri.shared_material->transparency > 0 && recursionDepth > 0)
    {
        //物体的折射率
        float ior = ci.tri.shared_material->indexOfRefraction;
        float etai = 1.0f, etat = ior;

        // 使用Schlick近似计算菲涅尔效应
        float R0 = (etai - etat) / (etai + etat);
        R0 = R0 * R0;
        //入射角余弦值
        float cosi = std::abs(intersectNormal.dot(r.direction.unit()));
        cosi = (cosi < -1.0) ? -1.0 : (cosi > 1.0) ? 1.0 : cosi;

        // Schlick逼近公式 计算反射系数
        float Reflectance = R0 + (1.0f - R0) * std::pow((1.0f-cosi),5) ;

        // 计算折射率之比
        float eta = etai / etat;

        // 使用斯涅尔定律计算是否发生全内反射
        float k = 1 - eta * eta * (1 - cosi * cosi);

        // 计算反射光线
        Ray reflectedRay = reflectRay(r, intersectNormal, Position);
        reflectedColor = RefractionWithFrensel(reflectedRay, recursionDepth - 1, weight);

        if(k > 0.0f){
            // 计算折射光线
            //std::cout<<"<no all>"<<std::endl;
            Ray refractedRay = refractRay(r, intersectNormal, Position, etai, etat);
            // 递归追踪折射光线
            refractedColor = RefractionWithFrensel(refractedRay, recursionDepth - 1, weight);
        }else{
            //std::cout<<"<all>"<<std::endl;
            refractedColor = ci.tri.shared_material->diffuse;
        }
        //std::cout<<"reflect:"<<ReflectanceIndex<<"refract:"<<refractedColor<<std::endl;
        color = Reflectance * reflectedColor + (1 - Reflectance) * refractedColor;
    }


    return color;

}


Homogeneous4 RaytraceRenderWidget::Montecarlosampling(Ray r,int recursionDepth,float weight)
{
    // 如果达到递归深度限制，则不再继续递归
    if (recursionDepth <= 0) {
        return Homogeneous4(0, 0, 0, 1); // 或者返回背景色或其他合适的默认颜色
    }
    //找到与光线相交的最近的三角形
    Scene::CollisionInfo ci = scene->closestTriangle(r);
    //定义颜色
    Homogeneous4 finalcolor(0,0,0,1);
    if(ci.t <= 0)return finalcolor;

    Homogeneous4 color(0,0,0,1);
    Homogeneous4 reflectedColor;
    Homogeneous4 refractedColor;
    Homogeneous4 indirectColor;
    Homogeneous4 directColor(0, 0, 0, 1); // 直接照明初始为黑色

    //计算交点P
    Cartesian3 intersectP = r.origin + ci.t * r.direction;
    //计算重心坐标
    Cartesian3 bc = ci.tri.baricentric(intersectP);
    //计算表面法线
    Cartesian3 intersectNormal = (ci.tri.normals[0].Vector() * bc.x +
                                  ci.tri.normals[1].Vector() * bc.y +
                                  ci.tri.normals[2].Vector() * bc.z).unit();
    //重心坐标插值 P
    Cartesian3 Position = ci.tri.verts[0].Point() * bc.x+
                          ci.tri.verts[1].Point() * bc.y+
                          ci.tri.verts[2].Point() * bc.z;

    //环境光
    Homogeneous4 ambientColor(ci.tri.shared_material->ambient.x,ci.tri.shared_material->ambient.y,ci.tri.shared_material->ambient.z,1);
    //自发光
    Homogeneous4 emittedColor(ci.tri.shared_material->emissive.x,ci.tri.shared_material->emissive.y,ci.tri.shared_material->emissive.z,1);

    //间接光照：
    //根据法线生成一个随机方向
    Cartesian3 randomDir = randomDirectionInHemisphere(intersectNormal);
    //生成随机光线
    Ray randomRay(Position + randomDir * 0.001f , randomDir);
    indirectColor =  indirectColor + Montecarlosampling(randomRay, recursionDepth - 1, weight  * ci.tri.shared_material->reflectivity);

    //定义环境光
    //移除现在的环境光
    //Homogeneous4 ambientlightcolor(0.5,0.5,0.5,1);
    ambientColor = indirectColor.modulate(ambientColor);

    //color = color + emittedColor +  ambientColor;


    //遍历每一条光线
    for (const Light* light : renderParameters->lights){
        //如果光亮
        if(light->enabled){

            // 计算光的颜色
            Matrix4 modelview = scene->getModelview();
            Homogeneous4 lightPosition = modelview * light->GetPositionCenter();
            Cartesian3 lighDirection=lightPosition.Point() - intersectP;
            float attenuation = 1.0f / (1.0f + pow(lighDirection.length(), 2));
            Homogeneous4 lightcolor = light->GetColor();
            //lightcolor = lightcolor * attenuation;
            //计算没有折射的表面颜色
            directColor = ci.tri.calculateBlinnPhongShading(lightPosition,lightcolor,bc)+ directColor + emittedColor + ambientColor;
        }
    }
    color = color + directColor + emittedColor + ambientColor;
    return color;

}

Cartesian3 RaytraceRenderWidget::randomDirectionInHemisphere(Cartesian3 normal)
{
//    //std::cout<<"randomDirectionInHemisphere"<<std::endl;
    static std::random_device rd;   // 随机数生成器的种子
    static std::mt19937 gen(rd());  // 随机数生成器
    static std::uniform_real_distribution<> dis(0, 1);  // 均匀分布的随机数

    // 使用余弦加权分布生成随机方向
    float r1 = dis(gen);
    float r2 = dis(gen);

    float sinTheta = sqrt(1 - r1);
    float phi = 2 * M_PI * r2;
    Cartesian3 randomDir(sinTheta * cos(phi), sinTheta * sin(phi), sqrt(r1));

    // 创建正交坐标系
    Cartesian3 w = normal.unit();
    Cartesian3 u = (Cartesian3(0.0f, 0.0f, 1.0f).cross(w)).unit();
    if (u.length() * u.length() < 0.001f) {
        u = (Cartesian3(0.0f, 1.0f, 0.0f).cross(w)).unit();
    }
    Cartesian3 v = w.cross(u);

    // 将随机方向转换到局部坐标系
    return u * randomDir.x + v * randomDir.y + w * randomDir.z;

}

void RaytraceRenderWidget::newRaytraceThread(){
    frameBuffer.clear(RGBAValue(0.0f, 0.0f, 0.0f,1.0f));
    scene->updateScene();
    int samplesPerPixel = 100;
    std::uniform_real_distribution<> dis(-0.1, 0.1);  // 像素内抖动的偏移量分布
    static std::random_device rd;   // 随机数生成器的种子
    std::mt19937 gen(rd());  // 随机数生成器

    for(int j = 0; j < frameBuffer.height; j++){
        for(int i = 0; i < frameBuffer.width; i++){
            Ray r=calculateRay(i,j,!renderParameters->orthoProjection);
            Homogeneous4 color;
            // Enable specular reflection
            if(renderParameters->reflectionEnabled){

            color = TraceAndShadeWithRay(r,N_BOUNCES,1.0f);
            }

            if(renderParameters->refractionEnabled){

            color = RefractionWithFrensel(r,N_BOUNCES,1.0f);
            }

            if(renderParameters->monteCarloEnabled){
            // 计算像素内的随机偏移位置
            float offsetX = dis(gen);
            float offsetY = dis(gen);
            // 生成抖动后的光线
            Ray r_monte = calculateRay(i, j, !renderParameters->orthoProjection);

            for (int s = 0; s < samplesPerPixel; s++) {

                color = color + Montecarlosampling(r_monte, 5, 0.8f);
            }
            // Average the color by the number of samples
            color = color * (1.0f / samplesPerPixel);
            }


            float gamma = 2.2f;
            //We already calculate everything in float, so we just do gamma correction
            //before putting it integer format.
            color.x = pow(color.x,1/gamma);
            color.y = pow(color.y,1/gamma);
            color.z = pow(color.z,1/gamma);
            frameBuffer[j][i] = RGBAValue(color.x*255.0f,
                                          color.y*255.0f,color.z*255.0f,255.0f);
        }
    }

}




//将在计算光线后的所有着色代码从主光线追踪循环中移到一个单独的函数中
// Moves all shading code from the main ray tracing loop to a separate function after the ray is computed
void RaytraceRenderWidget::RaytraceThread()
{
    frameBuffer.clear(RGBAValue(0.0f, 0.0f, 0.0f,1.0f));
    scene->updateScene();

    for(int j = 0; j < frameBuffer.height; j++){
        for(int i = 0; i < frameBuffer.width; i++){
        //Homogeneous4 color(i/float(frameBuffer.height),j/float(frameBuffer.width),0);
        Ray currentRay=calculateRay(i,j,!renderParameters->orthoProjection);
        Scene::CollisionInfo ci = scene->closestTriangle(currentRay);

        //-----------TASK4
        if(renderParameters->interpolationRendering){
            //calculate intersectP and bc
            Cartesian3 intersectP=currentRay.origin+ci.t*currentRay.direction;//计算交点
            Cartesian3 bc=ci.tri.baricentric(intersectP);//计算该交点的重心坐标
            //重心插值求法线
            //normOut 中存储的是通过重心坐标对三个顶点处法线进行插值后得到的法线向量，因此可以说它是通过重心坐标计算得到的法线,象征交点处的法线
            Cartesian3 normOut = (ci.tri.normals[0].Vector() * bc.x+
                                  ci.tri.normals[1].Vector() * bc.y+
                                  ci.tri.normals[2].Vector() * bc.z);
            Homogeneous4 color(abs(normOut.x),abs(normOut.y),abs(normOut.z),1);

            //frameBuffer[j][i]=RGBAValue(color.x*255.0f,color.y*255.0f,color.z*255.0f,255.0f);
            float gamma = 2.2f;
            //We already calculate everything in float, so we just do gamma correction
            //before putting it integer format.
            color.x = pow(color.x,1/gamma);
            color.y = pow(color.y,1/gamma);
            color.z = pow(color.z,1/gamma);
            frameBuffer[j][i] = RGBAValue(color.x*255.0f,
                                          color.y*255.0f,color.z*255.0f,255.0f);
        }

        //-----------TASK5
        if(renderParameters->phongEnabled){
            if(ci.t>0){
                    //计算重心坐标
                    Cartesian3 intersectP=currentRay.origin+ci.t*currentRay.direction;
                    Cartesian3 bc=ci.tri.baricentric(intersectP);
                    //交点处的法线
                    //重心坐标插值的目的是确保在三角形内的点的法线方向在三个顶点之间有一个平滑的过渡，而不是突然改变。
                    Cartesian3 intersectNormal = (ci.tri.normals[0].Vector() * bc.x +
                                                  ci.tri.normals[1].Vector() * bc.y +
                                                  ci.tri.normals[2].Vector() * bc.z).unit();
                    //initialize color
                    Homogeneous4 color(0,0,0,1);
                    Homogeneous4 ambientColor(ci.tri.shared_material->ambient.x,ci.tri.shared_material->ambient.y,ci.tri.shared_material->ambient.z,1);
                    Homogeneous4 emittedColor(ci.tri.shared_material->emissive.x,ci.tri.shared_material->emissive.y,ci.tri.shared_material->emissive.z,1);
                    //遍历每个光线
                    for (const Light* light : renderParameters->lights){
                        if(light->enabled){
                            Matrix4 modelview = scene->getModelview();
                            Homogeneous4 lightPosition = modelview * light->GetPositionCenter();

                            //从表面点到光源的向量
                            Cartesian3 lighDirection=lightPosition.Point()-intersectP;
                            float attenuation = 1.0f / (1.0f + pow(lighDirection.length(), 2));

                            Homogeneous4 lightcolor = light->GetColor();
                            lightcolor = lightcolor * attenuation;
                            //定义环境光
                            Homogeneous4 ambientlightcolor(0.5,0.5,0.5,1);
                            ambientColor = ambientlightcolor.modulate(ambientColor);

                            color = ci.tri.calculateBlinnPhongShading(lightPosition,lightcolor,bc)+ ambientColor +emittedColor + color;

                            //shadow
                            if(renderParameters->shadowsEnabled){

                                bool isShadowed = true;
                                //float epsilon=0.000001f;
                                float epsilon=0.01f;
                                // 生成阴影射线
                                Ray shadowRay(intersectP+intersectNormal*epsilon, lighDirection.unit());

                                // 检查阴影射线是否与其他物体相交
                                //Check if shadow rays intersect with other objects
                                Scene::CollisionInfo shadowCollision = scene->closestTriangle(shadowRay);

                                //如果阴影射线与其他物体相交
                                if(shadowCollision.t > 0){
                                    if(shadowCollision.tri.shared_material->isLight())
                                    {
                                        isShadowed=false;
                                    }

                                }
                                if(isShadowed){
                                    //Homogeneous4 ambientlightcolor(0.5,0.5,0.5,1);

                                    color = ambientColor + emittedColor;
                                }

                            }
                        }//phong-end

                    }

                    float gamma = 2.2f;
                    //We already calculate everything in float, so we just do gamma correction
                    //before putting it integer format.
                    color.x = pow(color.x,1/gamma);
                    color.y = pow(color.y,1/gamma);
                    color.z = pow(color.z,1/gamma);
                    frameBuffer[j][i] = RGBAValue(color.x*255.0f,
                                                  color.y*255.0f,color.z*255.0f,255.0f);
                }
           }//task56

        }

    }

    std::cout << "Done!" << std::endl;
}


void RaytraceRenderWidget::forceRepaint(){
    update();
}

//Casting a ray
Ray RaytraceRenderWidget::calculateRay(int pixelx, int pixely,bool perspective){
    float width=frameBuffer.width;
    float height=frameBuffer.height;

    //calculate screen aspect
    float aspect=width/height;

    //change to NDCs
    float ndcX = ((pixelx/width) - 0.5)*2;
    float ndcY = ((pixely/height) - 0.5)*2;

    if(aspect>1.0f){
        ndcX *= aspect;
    }else{
        ndcY /= aspect;
    }

    Cartesian3 rayOrigin;
    Cartesian3 rayDirection;
    //如果perspective为true，表示透视投影
    if(perspective){
        // 透视投影
        rayDirection = Cartesian3(ndcX, ndcY, -1.0f);
        rayOrigin = Cartesian3(0.0f, 0.0f, 1.0f);

    }
    else{
        rayDirection=Cartesian3(0.0f,0.0f,-1.0f);
        rayOrigin=Cartesian3(ndcX,ndcY,0.0f);
    }
    // 单位化射线方向
    rayDirection = rayDirection.unit();

    return Ray(rayOrigin,rayDirection);
}



//实现一个“reflectRay”函数，根据表面法线反射光线
Ray RaytraceRenderWidget::reflectRay(Ray r,Cartesian3 normal,Cartesian3 hitpoint){
    // 计算反射光线的方向
    Cartesian3 reflectionDirection = r.direction - 2.0f * (r.direction.dot(normal))*normal;
    return Ray(hitpoint+reflectionDirection*0.001f,reflectionDirection.unit());
}

//计算折射光线,光线，法线，击点，入射折射率，透射折射率
Ray RaytraceRenderWidget::refractRay(Ray r,Cartesian3 normal,Cartesian3 hitpoint,float etai, float etat)
{
    // 计算入射光线和法线之间的余弦值，确保其在-1.0到1.0之间
    Cartesian3 I = r.direction;

    //入射角余弦值
    float cosi = std::abs(normal.dot(I.unit()));
    // 计算折射率之比
    float eta = etai / etat;

    // 使用斯涅尔定律计算折射角
    float sin_t = eta * eta * (1 - cosi * cosi);
    float k = 1 - sin_t;

    //计算折射光线
    Cartesian3 refractionDirection;
    refractionDirection = eta * I + (eta * cosi - std::sqrt(k)) * normal;

    return Ray(hitpoint + refractionDirection * 0.001f, refractionDirection.unit());
}



